package com.czm.art_light.aspect;

import com.czm.art_light.annotation.DistributedLock;
import com.czm.art_light.constant.ArtErrorCodeEnum;
import com.czm.art_light.exception.BusinessException;
import com.czm.art_light.util.UserHolderUtility;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁AOP
 */
@Aspect
@Component
public class DistributedLockAspect {

    private static final String LOCK_PREFIX = "LOCK::";
    private static final String KEY_SEPARATOR = "::";

    @Autowired
    private RedissonClient redissonClient;

    private final ExpressionParser parser = new SpelExpressionParser();
    private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    @Around("@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
        // 1. 生成锁键
        String lockKey = buildLockKey(distributedLock, joinPoint);

        // 2. 获取分布式锁
        RLock lock = redissonClient.getLock(lockKey);
        boolean locked = false;

        try {
            // 3. 尝试获取锁（带超时时间）
            locked = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), TimeUnit.SECONDS);
            if (!locked) {
                throw new BusinessException(ArtErrorCodeEnum.GET_LOCK_ERROR);
            }

            // 4. 执行目标方法
            return joinPoint.proceed();
        } finally {
            // 5. 释放锁
            if (locked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 构建锁键
     */
    private String buildLockKey(DistributedLock distributedLock, ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Object[] args = joinPoint.getArgs();

        // 构建评估上下文
        EvaluationContext context = new MethodBasedEvaluationContext(
                null,
                method,
                args,
                parameterNameDiscoverer
        );

        // 解析SpEL表达式
        Expression expression = parser.parseExpression(distributedLock.lockKey());
        String keyValue = expression.getValue(context, String.class);

        // 组合完整锁键 LOCK::用户ID::KEY
        return LOCK_PREFIX + distributedLock.prefix() + KEY_SEPARATOR + UserHolderUtility.getUserId() + KEY_SEPARATOR + keyValue;
    }
}